#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# glumpy is an OpenGL framework for the fast visualization of numpy arrays.
# Copyright (C) 2009-2012  Nicolas P. Rougier. All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 
# THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# 
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of Nicolas P. Rougier.
# -----------------------------------------------------------------------------
'''
This is a demonstration for a grid shader that will be included in glumpy soon.
'''
import numpy as np
import OpenGL.GL as gl
from glumpy import figure, Trackball
from glumpy.graphics import VertexBuffer, Shader


if __name__ == '__main__':

    fig = figure(size=(512,512))
    trackball = Trackball(65, 135, 1., 3.)

    @fig.event
    def on_init():
        gl.glEnable( gl.GL_BLEND )
        gl.glEnable(gl.GL_NORMALIZE)
        gl.glEnable( gl.GL_LINE_SMOOTH )
        gl.glEnable( gl.GL_COLOR_MATERIAL )
        gl.glColorMaterial ( gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT_AND_DIFFUSE )
        gl.glBlendFunc (gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glEnable (gl.GL_LIGHTING)
        gl.glEnable (gl.GL_LIGHT0)
        gl.glEnable (gl.GL_LIGHT1)
        gl.glEnable (gl.GL_LIGHT2)

    @fig.event
    def on_mouse_drag(x, y, dx, dy, button):
        trackball.drag_to(x,y,dx,dy)
        fig.redraw()

    @fig.event
    def on_draw():
        fig.clear()
        trackball.push()

        major_grid = np.array([5.0, 5.0])
        minor_grid = np.array([50.0, 50.0])
        major_grid_color = np.array([0.75, 0.75, 0.75, 1.0])
        minor_grid_color = np.array([0.75, 0.75, 0.75, 1.0])
        major_grid_width = 1.50
        minor_grid_width = 0.25
        major_tick_size = 1.0/minor_grid
        minor_tick_size = 0.0/minor_grid
        major_tick_color = np.array([0.5, 0.5, 0.5, 1.0])
        minor_tick_color = np.array([0.5, 0.5, 0.5, 1.0])
        major_tick_width = 1.00
        minor_tick_width = 0.25

        shader.bind()
        shader.uniformf( 'major_grid',       *major_grid )
        shader.uniformf( 'minor_grid',       *minor_grid )
        shader.uniformf( 'major_grid_width',  major_grid_width )
        shader.uniformf( 'minor_grid_width',  minor_grid_width )
        shader.uniformf( 'major_grid_color', *major_grid_color )
        shader.uniformf( 'minor_grid_color', *minor_grid_color )
        shader.uniformf( 'major_tick_size',  *major_tick_size )
        shader.uniformf( 'minor_tick_size',  *minor_tick_size )
        shader.uniformf( 'major_tick_width',  major_tick_width )
        shader.uniformf( 'minor_tick_width',  minor_tick_width )
        shader.uniformf( 'major_tick_color', *major_tick_color )
        shader.uniformf( 'minor_tick_color', *minor_tick_color )
        vbuffer.draw( gl.GL_TRIANGLES, 'pnt' );
        shader.unbind()

        trackball.pop()

    V = np.array( [ ((-.5, -.5, -.5), (0,1,0), (0,0)),
                    ((+.5, -.5, -.5), (0,1,0), (0,1)),
                    ((+.5, -.5, +.5), (0,1,0), (1,1)),
                    ((-.5, -.5, +.5), (0,1,0), (1,0)),

                    ((-.5, -.5, -.5), (1,0,0), (0,0)),
                    ((-.5, +.5, -.5), (1,0,0), (0,1)),
                    ((-.5, +.5, +.5), (1,0,0), (1,1)),
                    ((-.5, -.5, +.5), (1,0,0), (1,0)),

                    ((-.5, -.5, -.5), (0,0,1), (0,0)),
                    ((-.5, +.5, -.5), (0,0,1), (0,1)),
                    ((+.5, +.5, -.5), (0,0,1), (1,1)),
                    ((+.5, -.5, -.5), (0,0,1), (1,0)) ],
                  dtype = [('position','f4',3),
                           ('normal','f4',3),
                           ('tex_coord','f4',2)] )
    I = np.array( [0,1,2, 0,2,3,
                   4,5,6, 4,6,7,
                   8,9,10, 8,10,11], dtype=np.uint32 )
    vbuffer = VertexBuffer(V,I)


    vertex = """
        varying vec2 T;
        void main()
        {
            gl_FrontColor = gl_Color;
            gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
            T = gl_MultiTexCoord0.st;
        }"""

    fragment = """
        varying vec2 T;
        uniform vec2  major_grid, minor_grid;
        uniform float major_grid_width, minor_grid_width;
        uniform vec4  major_grid_color, minor_grid_color;
        uniform vec2  major_tick_size,  minor_tick_size;
        uniform float major_tick_width, minor_tick_width;
        uniform vec4  major_tick_color, minor_tick_color;
        void main() 
        { 
            vec2 f, df, m;
            float c, c1, c2, c3, c4, c5, c6;

            // Major grid
            f = abs( fract (T*major_grid - vec2(0.5,0.5) ) - 0.5 );
            df = fwidth(T*major_grid);
            c = max(1.0,major_grid_width)/2.0;
            m = smoothstep( -(c-0.5)*df, +(c+0.5)*df, f );
            c = min(major_grid_width,1.0);
            c1 = 1.0 - c + c*m.x*m.y;

            // Minor grid
            f = abs( fract( T*minor_grid - vec2(0.5,0.5) )-0.5 );
            df = fwidth( T*minor_grid );
            c = max(1.0,minor_grid_width)/2.0;
            m = smoothstep( -(c-0.5)*df, +(c+0.5)*df, f );
            c = min(minor_grid_width,1.0);
            c2 = 1.0 - c + c*m.x*m.y;

            // Major ticks 
            c3 = c4 = 1.0;
            f = abs( fract( T*major_grid - vec2(0.5,0.5) )-0.5 );
            df = fwidth( T*major_grid );
            // c = max(1.0,major_tick_width)/2.0;
            // m = smoothstep( -(c-0.5)*df, +(c+0.5)*df, f );
            c = max(1.0,major_tick_width)/2.0;
            m = smoothstep( c*df, +(c+0.5)*df, f );
            c = min(major_tick_width,1.0);
            if( ( T.y < major_tick_size.y ) || ( T.y > (1.0-major_tick_size.y) ) )
            {
                c3 = 1.0 - c + c*m.x;
            }

            if( ( T.x < major_tick_size.x ) || ( T.x > (1.0-major_tick_size.x) ) )
            {
                c4 = 1.0 - c + c*m.y;
            }

            // Minor ticks 
            c5 = c6 = 1.0;
            f = abs( fract( T*minor_grid - vec2(0.5,0.5) )-0.5 );
            df = fwidth( T*minor_grid );
            // c = max(1.0,minor_tick_width)/2.0;
            // m = smoothstep( -(c-0.5)*df, +(c+0.5)*df, f );
            c = max(1.0,minor_tick_width)/2.0;
            m = smoothstep( c*df, +(c+0.5)*df, f );
            c = min(minor_tick_width,1.0);
            if( ( T.y < minor_tick_size.y ) || ( T.y > (1.0-minor_tick_size.y) ) )
            {
                c5 = 1.0 - c + c*m.x;
            }

            if( ( T.x < minor_tick_size.x ) || ( T.x > (1.0-minor_tick_size.x) ) )
            {
                c6 = 1.0 - c + c*m.y;
            }

            c = min( min(c1,c2), min(c3,c4) );
            c = min( c, min(c5,c6) );

            vec4 color;
            if( (c == c3) || (c == c4) )
               color = major_tick_color;
            else if( (c == c5) || (c == c6) )
               color = minor_tick_color;
            else if( c == c2 )
               color = minor_grid_color;
            else
               color = major_grid_color;

            gl_FragColor = mix( color, vec4(1.0,1.0,1.0,1.0), c );
        }"""
    shader = Shader(vertex,fragment)

    fig.show()
